package model

import (
	"encoding/base64"
	"ginblog/utils/errormsg"
	"golang.org/x/crypto/scrypt"
	"gorm.io/gorm"
	"log"
)

//var code int

type User struct {
	gorm.Model
	Username string `gorm:"type:varchar(20)" json:"username" validate:"required,min=4,max=20" label:"用户名"`
	Password string `gorm:"type:varchar(20)" json:"password" validate:"required,min=6,max=20" label:"密码"`
	Role     int    `gorm:"type:int;DEFAULT:2" json:"role" validate:"required gte=2" label:"角色码"`
}

// CheckUser 查询用户是否存在
func CheckUser(username string) int {
	var user User
	db.Select("id").Where("username = ?", username).First(&user)
	if user.ID > 0 {
		return errormsg.ERROR_USERNAME_USED //用户名称已存在
	}

	return errormsg.SUCCESS // 成功状态码
}

// AddUser 增加用户
func AddUser(user *User) int {
	user.Password = ScryptPw(user.Password)
	err := db.Create(user).Error
	if err != nil {
		return errormsg.ERROR
	}
	return errormsg.SUCCESS
}

// GetUsers 获取用户列表
func GetUsers(pageSize int, pageNum int) ([]User, int64) {
	var users []User
	var total int64
	err := db.Limit(pageSize).Offset((pageNum - 1) * pageSize).Find(&users).Count(&total).Error
	//err := db.Limit(pageSize).Offset(0).Find(&users).Error
	//offset 里面的参数表示查询操作要调过的数据
	if err != nil {
		return nil, 0
	}
	return users, total
}

// ScryptPw 密码加密
func ScryptPw(password string) string {
	const (
		KeyLen = 32    // 生成的密钥长度
		N      = 16384 // CPU/内存成本因子 值为 2的幂次
		r      = 8     // 块大小
		p      = 1     // 并行因子
	)
	salt := make([]byte, 8) // 创建一个盐  它的长度为8

	// 实际程序中应该随机生成，而不是直接使用硬编码
	// 为了后续验证登陆的方便，也可以直接将这个随机生成的盐值和使用这个盐值生成的密码一同存储到数据库里面
	salt = []byte{12, 32, 4, 6, 66, 22, 222, 11}

	// 通过盐值获得密码哈希值(经过 scrypt 算法派生的密钥字节切片（[] byte）。)
	HashPw, err := scrypt.Key([]byte(password), salt, N, r, p, KeyLen)

	if err != nil {
		log.Fatal(err)
	}

	// 对上面生成的密码哈希值进行了一次可读性的转换 便于数据的存储
	fpw := base64.StdEncoding.EncodeToString(HashPw)

	return fpw
}

// DeleteUser 删除用户
func DeleteUser(id int) int {
	err := db.Where("id = ?", id).Delete(&User{}).Error
	if err != nil {
		return errormsg.ERROR
	}
	return errormsg.SUCCESS
}

// UpdateUser 编辑用户
func UpdateUser(id int, newUser *User) int {
	//var user User
	// 不修改密码 只修改用户名称和角色
	var data = map[string]interface{}{}
	data["username"] = newUser.Username
	data["role"] = newUser.Role
	err = db.Model(&User{}).Where("id = ?", id).Updates(data).Error
	// 这个Model里传入的参数可以是 &user 也可以是&User{} 主要就是为了让编辑器知道具体要操作的表示哪一张 编辑器可以通过user推断出是User这张表
	if err != nil {
		return errormsg.ERROR
	}
	return errormsg.SUCCESS
}

// CheckLogin 登陆验证
func CheckLogin(username, password string) int {
	var user User

	db.Where("username = ?", username).First(&user)

	if user.ID == 0 {
		return errormsg.ERROR_USER_NOT_EXIST
	}
	if user.Password != ScryptPw(password) {
		return errormsg.ERROR_PASSWORD_WRONG
	}

	if user.Role != 0 {
		return errormsg.ERROR_USER_NOT_RIGHT
	}
	return errormsg.SUCCESS
}
